package com.alibaba.citrus.ots.application.report.ability.repository.impl;

import com.alibaba.citrus.ots.application.report.ability.repository.BaseInventoryImportRepository;
import com.alibaba.citrus.ots.application.report.ability.repository.PlatformRepository;
import com.alibaba.citrus.ots.application.report.ability.utils.DomUtil;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.citrus.ots.common.util.ThreadPageUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.BaselineBatchQueryPlatformsRequest;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByIds2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByIds2Response;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByOutCodes2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByOutCodes2Response;
import com.epoch.app.bcorder.model.dto.OrganizationSDO;
import com.epoch.app.bcorder.model.dto.SearchWarehouseForPlatformNewRequest;
import com.epoch.app.bcorder.model.dto.SearchWarehouseForPlatformNewResponse;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.BcOrderService;
import com.epoch.app.crplatformenhance.domain.customeraddress.dto.BatchQueryByIdsRequest;
import com.epoch.app.crplatformenhance.domain.customeraddress.model.CustomerAddress;
import com.epoch.app.crplatformenhance.domain.customeraddress.service.CustomerAddressService;
import com.epoch.app.crunifiedinventory.model.dto.GetInventoryForAnalysisRequest;
import com.epoch.app.crunifiedinventory.model.dto.GetInventoryTotalForAnalysisRequest;
import com.epoch.app.crunifiedinventory.model.dto.GetInventoryTotalForAnalysisResponse;
import com.epoch.app.crunifiedinventory.model.dto.GetListWarehouseStockRequest;
import com.epoch.app.crunifiedinventory.model.dto.InventoryForAnalysisResp;
import com.epoch.app.crunifiedinventory.model.dto.OuiWareshouseIndexRequest;
import com.epoch.app.crunifiedinventory.model.dto.WarehouseInventory;
import com.epoch.app.crunifiedinventory.model.enums.AllocateOrderStatus;
import com.epoch.app.crunifiedinventory.ouiwarehouse.model.OuiWarehouse;
import com.epoch.app.crunifiedinventory.sdo.enums.AllocateOrderTypeEnum;
import com.epoch.app.crunifiedinventory.service.CrUnifiedInventoryService;
import com.epoch.app.otsapplicationreportsdk.contants.OtsApplicationReportSdkConstants;
import com.epoch.app.otsapplicationreportsdk.ecinventorydetail.dto.BatchAddRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorydetail.dto.BatchUpdateRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorydetail.dto.LoadListRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorydetail.model.EcInventoryDetail;
import com.epoch.app.otsapplicationreportsdk.ecinventorydetail.service.EcInventoryDetailService;
import com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.BatchCreateRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.LoadListReadOnlyRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.QueryByWarehouseIdsRequest;
import com.epoch.app.otsapplicationreportsdk.ecinventorystats.model.EcInventoryStats;
import com.epoch.app.otsapplicationreportsdk.ecinventorystats.service.EcInventoryStatsService;
import com.epoch.app.otsapplicationreportsdk.model.dto.GoodsDO;
import com.epoch.app.otsapplicationreportsdk.model.enums.InventoryTypeEnum;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.dto.QueryAllocateOrderDetailReportFtobRequest;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.model.OarsAllocateOrderDetailReportFtob;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.service.OarsAllocateOrderDetailReportFtobService;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftof1.dto.QueryAllocateOrderDetailReportFtof1Request;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftof1.model.OarsAllocateOrderDetailReportFtof1;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftof1.service.OarsAllocateOrderDetailReportFtof1Service;
import com.google.common.collect.Lists;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service
public class EcShareInventoryImportImpl implements BaseInventoryImportRepository {

    private final Log log = Log.getLogger(WarehouseInventoryImportImpl.class);

    private static final int PAGE_NO_1 = 1;

    private static final int PAGE_SIZE_500 = 500;

    private static final String FILTER_STR = "到场";

    /**
     * 汇总库存
     */
    private static final String SUMMARY_INVENTORY_TYPE = "1";
    private static final String NM_MARKETING_LTD = "297930135641736761";

    @Resource
    EcInventoryDetailService ecInventoryDetailService;

    @Resource
    EcInventoryStatsService ecInventoryStatsService;

    @Resource
    CrUnifiedInventoryService otsUnifiedInventoryService;

    @Resource
    BaseDataService baseDataService;

    @Resource
    BcOrderService bcOtsService;

    @Resource
    OarsAllocateOrderDetailReportFtobService oarsAllocateOrderDetailReportFtobService;

    @Resource
    OarsAllocateOrderDetailReportFtof1Service oarsAllocateOrderDetailReportFtof1Service;

    @Resource
    CustomerAddressService customerAddressService;

    @Resource
    PlatformRepository platformRepository;

    @Resource(name = "inventorySyncTaskExecutor")
    ThreadPoolTaskExecutor inventorySyncTaskExecutor;

    //拉取库存原子信息
    @Override
    public List<WarehouseInventory> getInventoryList(List<String> warehouseAreaIds, Integer size) {
        StopWatch stopwatch = new StopWatch();
        List<Future<List<WarehouseInventory>>> futureList = Lists.newArrayList();
        stopwatch.start("getTotal");
        GetInventoryTotalForAnalysisRequest request = new GetInventoryTotalForAnalysisRequest();
        request.setType(InventoryTypeEnum.WARE_HOUSE.getType());
        request.setWarehouseAreaIdList(warehouseAreaIds);
        GetInventoryTotalForAnalysisResponse totalResult = otsUnifiedInventoryService.getInventoryTotalForAnalysis(request);
        int totalCnt = totalResult.getResult();
        stopwatch.stop();
        log.info("warehouseInventoryImportImpl_getInventoryTotal={},use_time={}ms", totalCnt,
            stopwatch.getTotalTimeSeconds());
        int newsize = (size != null && !size.equals(0)) ? size : PAGE_SIZE_500;
        int totalPage = ThreadPageUtil.calculateTotalPage(totalCnt, newsize);
        for (int pageNo = PAGE_NO_1; pageNo <= totalPage; pageNo++) {
            int finalPageNo = pageNo;
            CompletableFuture<List<WarehouseInventory>> future = CompletableFuture.supplyAsync(() -> {
                List<WarehouseInventory> listResult = null;
                GetInventoryForAnalysisRequest futurerequest = new GetInventoryForAnalysisRequest();
                futurerequest.setType(InventoryTypeEnum.WARE_HOUSE.getType());
                futurerequest.setPage(finalPageNo);
                futurerequest.setSize(newsize);
                futurerequest.setWarehouseAreaIdList(warehouseAreaIds);
                try {
                    Result<List<InventoryForAnalysisResp>> resp = otsUnifiedInventoryService.getInventoryForAnalysis(futurerequest);
                    if (resp.isSuccess() && CollectionUtils.isEmpty(resp.getResult())) {
                        return Lists.newArrayList();
                    }
                    listResult = formatQuantity(resp.getResult());
                } catch (Exception e) {
                    log.error("warehouseInventoryImportImpl_pull_getListWarehouseStock_error={}", e.getMessage());
                }
                log.error("warehouseInventoryImportImpl_pull_getListWarehouseStock_info={},resultSize={}",
                    JSON.toJSON(futurerequest), listResult.size());
                return listResult;
            }, inventorySyncTaskExecutor);
            futureList.add(future);
        }
        List<WarehouseInventory> result = new ArrayList<>();
        try {
            stopwatch.start("listwarehouseinventory");
            int futureTimes = 1;
            for (Future<List<WarehouseInventory>> future : futureList) {
                List<WarehouseInventory> inventorySubList = future.get();
                result.addAll(inventorySubList);
                futureTimes++;
            }
            stopwatch.stop();
            log.info("warehouseInventoryImportImpl_use_time={}s,foreachtimes={}s,inventorySubList_size={}",
                stopwatch.getTotalTimeSeconds(), futureTimes, result.size());
        } catch (Exception e) {
            log.error("warehouseInventoryImportImpl_pull_getListWarehouseStock_wait_occur_error={}", e.getMessage());
        }
        log.info("getInventoryList_stopWatch_prettyPrint={}", stopwatch.prettyPrint());
        return result;
    }

    @Override
    public List<WarehouseInventory> getInventoryList() {
        List<Future<List<WarehouseInventory>>> futureList = Lists.newArrayList();
        int totalCnt = getInventoryTotal(InventoryTypeEnum.WARE_HOUSE);
        log.info("ecShareInventoryImportImpl_getInventoryTotal={}", totalCnt);
        int totalPage = totalCnt / PAGE_SIZE_500;
        if (totalCnt % PAGE_SIZE_500 > 0) {
            totalPage++;
        }
        for (int pageNo = 1; pageNo <= totalPage; pageNo++) {
            int finalPageNo = pageNo;
            CompletableFuture<List<WarehouseInventory>> future = CompletableFuture.supplyAsync(() -> {
                Result<List<WarehouseInventory>> listResult = null;
                GetListWarehouseStockRequest request = new GetListWarehouseStockRequest();
                // 当前类型与库存侧列表页查询保持一致
                /**
                 * 库存列表中的库存查询为汇总库存，类型为1
                 */
                request.setType(String.valueOf(InventoryTypeEnum.WARE_HOUSE.getType()));
                //request.setType(SUMMARY_INVENTORY_TYPE);
                request.setPage(finalPageNo);
                request.setSize(PAGE_SIZE_500);
                /**
                 * 20220411
                 * 按产品要求，目前写死内蒙古数科数字营销有限公司组织id，只查询电商数科数据
                 */
                request.setBizUnitIdList(Lists.newArrayList(NM_MARKETING_LTD));
                // 与库存侧列表页查询保持一致
                //request.setSearchForPage(Boolean.TRUE);
                try {
                    listResult = otsUnifiedInventoryService.getListWarehouseStock(request);
                    if (listResult == null || CollectionUtils.isEmpty(listResult.getResult())) {
                        return Lists.newArrayList();
                    }
                } catch (Throwable e) {
                    log.error("step_ecShareInventoryImportImpl_one_error={}", e.getMessage());
                    return Lists.newArrayList();
                }
                return listResult.getResult();
            }, inventorySyncTaskExecutor);
            futureList.add(future);
        }
        List<WarehouseInventory> result = new ArrayList<>();
        try {
            for (Future<List<WarehouseInventory>> future : futureList) {
                if (Objects.isNull(future)) {
                    continue;
                }
                try {
                    List<WarehouseInventory> inventorySubList = future.get();
                    if (CollectionUtils.isEmpty(inventorySubList)) {
                        log.info("Step_ecShareInventoryImportImpl_inventorySubList_result_is_null={}",
                            inventorySubList);
                        continue;
                    }
                    //    inventorySubList = inventorySubList.stream().filter(s->isEcWarehouse(s.getWarehouseAreaId()
                    //    ,ecWarehouseIds)).collect(Collectors.toList());
                    result.addAll(inventorySubList);
                } catch (Throwable e) {
                    log.error("Step_ecShareInventoryImportImpl_two_多线程获取结果异常={}", e);
                }
            }
        } catch (Exception e) {
            log.error("Step_ecShareInventoryImportImpl_third_获取多线程查询结果异常={}", e);
        }
        return result;
    }

    //统计数据入库
    @Override
    public void doImportData(List<WarehouseInventory> importInventoryList, List<String> importWarehouseAreaIds, Map<String, GoodsDO> goodsDOMap, boolean firstSyncOfToday) {
        //查询 1900021273 内蒙古数科数字营销有限公司 组织信息
        OrganizationSDO companyOrg = allocateOrderByCode("1900021273");
        // 获取库存数据的逻辑仓
        Set<String> inventoryWarehouseAreaId = getInventoryWarehouseAreaId(importInventoryList);
        //查询 1171销售组织的共享仓的所有关联平台
        // Set<String> platformIds = platformRepository.getWarehouseByPlatFormCodes();
        //获取1171销售组织的电商仓 且在本次传入的逻辑仓范围内的
        List<EcWarehouse> warehouseList = getEcWarehouseInfo(inventoryWarehouseAreaId);
        log.info("ecShareInventoryImportImpl_ecWarehouseList_size={},{}", warehouseList.size(),JSON.toJSONString(warehouseList));
        //获取电商组织的共享仓中含有"到场"字样的仓库id 且在本次传入的逻辑仓范围内的
        Set<String> filterWarehouseId = filterWarehouseAreaId(warehouseList);
        log.info("ecShareInventoryImportImpl_filterWarehouseId={}", JSONObject.toJSONString(filterWarehouseId));
        //获取发货数量(已出库数量)
        Map<String, Long> shipQuantityMap = getShipQuantity(companyOrg, inventoryWarehouseAreaId);
        log.info("ecShareInventoryImportImpl_shipQuantityMap_size={},{}", shipQuantityMap.size(),JSON.toJSONString(shipQuantityMap));
        //获取调拨未到货数量
        Map<String, Long> notArriveQuantityMap = getNotArriveQuantity(companyOrg, filterWarehouseId,inventoryWarehouseAreaId);
        log.info("ecShareInventoryImportImpl_notArriveQuantityMap_size={},{}", notArriveQuantityMap.size(),JSON.toJSONString(notArriveQuantityMap));

        List<EcInventoryStats> statsList = new ArrayList<>();
        Map<String, List<WarehouseInventory>> mapOrg = importInventoryList.stream().collect(Collectors.groupingBy(WarehouseInventory::getWarehouseAreaId));
        //仓x货品维度统计信息入库
        List<EcInventoryDetail> detailList = new ArrayList<>();
        for (Map.Entry<String, List<WarehouseInventory>> entryOrg : mapOrg.entrySet()) {
            String warehouseAreaId = entryOrg.getKey();
            Map<String, List<WarehouseInventory>> mapItem = entryOrg.getValue().stream().collect(Collectors.groupingBy(WarehouseInventory::getGoodsId));
            for (Map.Entry<String, List<WarehouseInventory>> entryItem : mapItem.entrySet()) {
                EcInventoryDetail detail = collectInventoryDetail(entryItem, goodsDOMap, shipQuantityMap,notArriveQuantityMap);
                if (detail != null) {
                    detailList.add(detail);
                }
            }
        }

        for (Map.Entry<String, Long> entry : shipQuantityMap.entrySet()) {
            // 销售调拨单中不存在库存的唯一key，需要以调拨为基础，补充库存信息
            EcInventoryDetail detail = collectInventoryDetail(entry, parseOuterItemIdMap(goodsDOMap),notArriveQuantityMap);
            if (detail != null) {
                detailList.add(detail);
            }
        }

        for (Map.Entry<String, Long> entry : notArriveQuantityMap.entrySet()) {
            // 计划调拨单中不存在库存的唯一key，需要以调拨为基础，补充库存信息
            EcInventoryDetail detail = collectInventoryDetail(entry, parseOuterItemIdMap(goodsDOMap), null);
            if (detail != null) {
                detailList.add(detail);
            }
        }

        List<String> notHitWareHouseId = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(detailList)) {
            log.info("ecShareInventoryImportImpl_detailList_size={}", detailList.size());
            Map<String, List<EcInventoryDetail>> map = detailList.stream().collect(Collectors.groupingBy(EcInventoryDetail::getWarehouseId));
            for (Map.Entry<String, List<EcInventoryDetail>> entryOrg : map.entrySet()) {
                String warehouseAreaId = entryOrg.getKey();
                List<EcInventoryDetail> orgInventoryList = entryOrg.getValue();

                enrichPlatInfo(warehouseAreaId, orgInventoryList, warehouseList);
                //20222-05-06 按产品牧常要求
                //未匹配到电商下的共享仓、工厂仓的数据不需要落库
                if (CollectionUtils.isNotEmpty(orgInventoryList) && StringUtils.isEmpty(orgInventoryList.get(0).getWarehouseCode())){
                    notHitWareHouseId.add(warehouseAreaId);
                    continue;
                }
                saveInventoryDetail(warehouseAreaId, orgInventoryList, firstSyncOfToday);
                EcInventoryStats stats = collectInventoryStats(orgInventoryList);
                statsList.add(stats);
            }
        }
        log.info("unreached_warehouareaId:{}", JSONObject.toJSONString(notHitWareHouseId));
        //仓维度统计信息入库
        if (CollectionUtils.isNotEmpty(statsList)) {
            saveInventoryStats(statsList, firstSyncOfToday);
        }
        log.info("ecShareInventoryImportImpl_statsList_size={}", statsList.size());

        //报表数据没做对比的，报表库存全部置为0
        if(!firstSyncOfToday){
            String statisticalDate = DomUtil.getToday();
            List<String> notCompareWarehouseIds = importWarehouseAreaIds.stream().filter(x->!inventoryWarehouseAreaId.contains(x)).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(notCompareWarehouseIds)){
                return;
            }
            QueryByWarehouseIdsRequest queryRequest = new QueryByWarehouseIdsRequest();
            queryRequest.setStatisticalDate(statisticalDate);
            queryRequest.setWarehouseIds(notCompareWarehouseIds);
            Result<List<EcInventoryStats>> reportQueryResult = ecInventoryStatsService.queryByWarehouseIds(queryRequest);
            if(Objects.nonNull(reportQueryResult) && CollectionUtils.isNotEmpty(reportQueryResult.getResult())){
                List<String> updateWarehouseIds = reportQueryResult.getResult().stream()
                        .filter(x->!isZeroInventoryQuantity(null,x))
                        .map(x->x.getWarehouseId()).collect(Collectors.toList());
                log.info("ecShareInventoryImportImpl_notCompareWarehouseIds={}", JSONObject.toJSONString(updateWarehouseIds));

                if(CollectionUtils.isNotEmpty(updateWarehouseIds)){
                    EcInventoryDetail detailUpdate = new EcInventoryDetail();
                    EcInventoryStats statsUpdate = new EcInventoryStats();
                    initZeroInventoryQuantity(detailUpdate,statsUpdate);
                    BatchUpdateRequest batchUpdateDetailRequest = new BatchUpdateRequest();
                    BeanUtils.copyProperties(detailUpdate,batchUpdateDetailRequest);
                    batchUpdateDetailRequest.setStatisticalDate(statisticalDate);
                    batchUpdateDetailRequest.setWarehouseIds(updateWarehouseIds);
                    ecInventoryDetailService.batchUpdate(batchUpdateDetailRequest);
                    com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.BatchUpdateRequest batchUpdateStatsRequest = new com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.BatchUpdateRequest();
                    BeanUtils.copyProperties(statsUpdate,batchUpdateStatsRequest);
                    batchUpdateStatsRequest.setStatisticalDate(statisticalDate);
                    batchUpdateStatsRequest.setWarehouseIds(updateWarehouseIds);
                    ecInventoryStatsService.batchUpdate(batchUpdateStatsRequest);
                }
            }
        }
    }

    private void saveInventoryDetail(String warehouseId, List<EcInventoryDetail> todoList,boolean firstSyncOfToday) {
        //当天首次同步则直接插入
        if (firstSyncOfToday) {
            BatchAddRequest batchAddRequest = new BatchAddRequest();
            batchAddRequest.setReportList(todoList);
            Object result = ecInventoryDetailService.batchAdd(batchAddRequest);
        } else {
            //根据目前纪元单次最多只能查出1000条的数据限制，若未来单仓出现全链路明细超过1000条，会存在重复数据风险
            LoadListRequest request = new LoadListRequest();
            request.setWarehouseId(warehouseId);
            request.setStatisticalDate(DomUtil.getToday());
            request.setStart(0);
            request.setLimit(2000);
            Result<List<EcInventoryDetail>> response;
            if ("1".equals(OtsApplicationReportSdkConstants.QUERY_READONLY_DATABASE())) {
                com.epoch.app.otsapplicationreportsdk.ecinventorydetail.dto.LoadListReadOnlyRequest readOnlyRequest
                    = new com.epoch.app.otsapplicationreportsdk.ecinventorydetail.dto.LoadListReadOnlyRequest();
                BeanUtils.copyProperties(request, readOnlyRequest);
                response = ecInventoryDetailService.loadListReadOnly(readOnlyRequest);
            } else {
                response = ecInventoryDetailService.loadList(request);
            }
            List<EcInventoryDetail> existedList = new ArrayList<>();
            if (Objects.nonNull(response) && CollectionUtils.isNotEmpty(response.getResult())) {
                existedList = response.getResult();
            }
            for (EcInventoryDetail todo : todoList) {
                //已存在的数据则更新
                EcInventoryDetail existed = existedOfList(todo, existedList);
                if (existed != null) {
                    if (!needUpdate(todo, existed)) {
                        existed.setUpdater("1");
                        log.info("EcInventoryDetail_exist_and_nochanged，id={}", existed.getId());
                        continue;
                    }
                    BeanUtils.copyProperties(todo, existed, "id");
                    existed.setGmt_modified(new Date());
                    Object updateResponse = ecInventoryDetailService.update(existed);
                    existed.setUpdater("1");
                } else {
                    Object createResponse = ecInventoryDetailService.create(todo);
                }
            }

            //报表数据没做对比的，报表库存全部置为0
            List<EcInventoryDetail> notCompareDetailList = existedList.stream()
                    .filter(x->!"1".equals(x.getUpdater()))
                    .filter(x->!isZeroInventoryQuantity(x,null))//过滤库存已经是0的不做数据库变更
                    .collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(notCompareDetailList)){
                List<Long> ids = notCompareDetailList.stream().map(x->x.getId()).collect(Collectors.toList());
                log.info("EcInventoryDetail_exist_and_notCompareDetail,warehouseId={},list={}", warehouseId,JSONObject.toJSONString(ids));
                for (EcInventoryDetail detail : notCompareDetailList) {
                    initZeroInventoryQuantity(detail,null);
                    Object updateResponse = ecInventoryDetailService.update(detail);
                }
            }
        }
    }

    //判断是否为当天第一次同步
    @Override
    public boolean firstSyncOfToday() {
        com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.LoadListRequest request
            = new com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.LoadListRequest();
        request.setStatisticalDate(DomUtil.getToday());
        return CollectionUtils.isEmpty(ecInventoryStatsService.loadList(request).getResult());
    }

    //判断重要指标是否有变化
    private boolean needUpdate(EcInventoryDetail todo, EcInventoryDetail existed) {
        return !todo.getTotalQuantity().equals(existed.getTotalQuantity()) ||
            !todo.getAvailableQuantity().equals(existed.getAvailableQuantity()) ||
            !todo.getWithholdingQuantity().equals(existed.getWithholdingQuantity()) ||
            !todo.getOnwayQuantity().equals(existed.getOnwayQuantity()) ||
            !todo.getShipQunatity().equals(existed.getShipQunatity()) ||
            !todo.getNotArriveQuantity().equals(existed.getNotArriveQuantity());
    }

    //判断重要指标是否有变化
    private boolean needModify(EcInventoryStats todo, EcInventoryStats existed) {
        return !todo.getTotalQuantity().equals(existed.getTotalQuantity()) ||
            !todo.getAvailableQuantity().equals(existed.getAvailableQuantity()) ||
            !todo.getWithholdingQuantity().equals(existed.getWithholdingQuantity()) ||
            !todo.getOnwayQuantity().equals(existed.getOnwayQuantity()) ||
            !todo.getNotArriveQuantity().equals(existed.getNotArriveQuantity());
    }

    private void saveInventoryStats(List<EcInventoryStats> todoList, boolean firstSyncOfToday) {
        //当天首次同步则直接插入
        if (firstSyncOfToday) {
            BatchCreateRequest batchCreateRequest = new BatchCreateRequest();
            batchCreateRequest.setReportList(todoList);
            Object result = ecInventoryStatsService.batchCreate(batchCreateRequest);
        } else {
            //分析条数超过2000会有问题, 暂时电商仓不会超过5000条。线上不到200条。 当超过2000条时要改。
            com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.LoadListRequest request
                = new com.epoch.app.otsapplicationreportsdk.ecinventorystats.dto.LoadListRequest();
            request.setStatisticalDate(DomUtil.getToday());
            request.setStart(0);
            request.setLimit(2000);
            Result<List<EcInventoryStats>> response = null;
            if ("1".equals(OtsApplicationReportSdkConstants.QUERY_READONLY_DATABASE())) {
                LoadListReadOnlyRequest readOnlyRequest = new LoadListReadOnlyRequest();
                BeanUtils.copyProperties(request, readOnlyRequest);
                response = ecInventoryStatsService.loadListReadOnly(readOnlyRequest);
            } else {
                response = ecInventoryStatsService.loadList(request);
            }
            List<EcInventoryStats> existedList = new ArrayList<>();
            if (Objects.nonNull(response) && CollectionUtils.isNotEmpty(response.getResult())){
                existedList = response.getResult();
            }
            for (EcInventoryStats todo : todoList) {
                //已存在的数据则更新
                EcInventoryStats existed = existedOfList(todo, existedList);
                if (existed != null) {
                    if (!needModify(todo, existed)) {
                        log.info("EcInventoryStats_exist_and_nochanged,id={}", existed.getId());
                        continue;
                    }
                    BeanUtils.copyProperties(todo, existed, "id");
                    existed.setGmt_modified(new Date());
                    Object updateResponse = ecInventoryStatsService.update(existed);
                } else {
                    Object createResponse = ecInventoryStatsService.create(todo);
                }
            }
        }
    }

    @FacadeInvoker
    public Map<String, Long> getShipQuantity(OrganizationSDO companyOrg, Set<String> inventoryWarehouseAreaId) {
        if (ObjectUtils.isEmpty(companyOrg)) {
            return new HashMap<>();
        }
        Map<String, Long> resultMap = new HashMap<>();
        // F->b/F1->b调拨单  查询正向的
        int start = 0;
        int limit = 500;
        Date todayDate = DateUtils.getFirstTime(new Date());
        QueryAllocateOrderDetailReportFtobRequest request = QueryAllocateOrderDetailReportFtobRequest.builder()
            .mainShipAreaId(Lists.newArrayList(inventoryWarehouseAreaId))
            //.platformIds(Lists.newArrayList(platformIds))
            .platformNullId(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())
            .applyOrgIds(Lists.newArrayList(companyOrg.getId()))
            .type(AllocateOrderTypeEnum.HEADQUARTER_SALES.getType())
            .warehouseTypes(Lists.newArrayList(2, 5)) //共享仓、工厂仓
            .isDTC(1)
            //.mainReturnOrder(0)
            .subStatuss(Lists.newArrayList(AllocateOrderStatus.DRAFT.getValue(),
                AllocateOrderStatus.Shipment_Processing.getValue(),
                AllocateOrderStatus.Part_Shipped.getValue(),
                AllocateOrderStatus.Received.getValue(),
                AllocateOrderStatus.Shipped.getValue(),
                AllocateOrderStatus.Receive_Processing.getValue(),
                AllocateOrderStatus.Part_Received.getValue(),
                AllocateOrderStatus.WAIT_PUSH.getValue(),
                AllocateOrderStatus.CLOSED_AND_PARTSHIPPED.getValue(),
                AllocateOrderStatus.CLOSED_AND_PARTRECEIVED.getValue()))
            .startTime(DateUtils.parse(DomUtil.getRollbackDate(todayDate, -90)))
            .endTime(DateUtils.getLatestTime(todayDate))
            .start(start)
            .limit(limit)
            .build();
        try {
            Result<List<OarsAllocateOrderDetailReportFtob>> listResult = oarsAllocateOrderDetailReportFtobService
                .queryAllocateOrderDetailReportFtob(request);
            log.info("ecShareInventoryImportImpl_getShipQuantity_query_request={},size={}", JSON.toJSONString(request),
                listResult.getTotal());
            int allPage = listResult.getTotal() / limit;
            if (listResult.getTotal() % limit > 0) {
                allPage += 1;
            }
            if (ObjectUtils.isEmpty(listResult)) {
                return new HashMap<>();
            }
            List<OarsAllocateOrderDetailReportFtob> oarsAllocateOrderDetailReportFtobs = listResult.getResult();
            if (CollectionUtils.isEmpty(oarsAllocateOrderDetailReportFtobs)) {
                return new HashMap<>();
            }
            for (int i = 1; i < allPage; i++) {
                start = limit * i;
                request.setStart(start);
                Result<List<OarsAllocateOrderDetailReportFtob>> listResult1 = oarsAllocateOrderDetailReportFtobService.queryAllocateOrderDetailReportFtob(request);
                if (!ObjectUtils.isEmpty(listResult1) && !CollectionUtils.isEmpty(listResult1.getResult())) {
                    oarsAllocateOrderDetailReportFtobs.addAll(listResult1.getResult());
                }
            }

            oarsAllocateOrderDetailReportFtobs.forEach(x -> {
                if(!inventoryWarehouseAreaId.contains(x.getMainShipAreaId())) {
                    return;
                }
                // 交货数量
                Integer deliveryQuantity = StringUtils.isEmpty(x.getSubDeliveryQuantity()) ? 0 : new BigDecimal(x.getSubDeliveryQuantity()).intValue();
                // 发货数量
                Integer shipQuantity = StringUtils.isEmpty(x.getSubShipQuantity()) ? 0: x.getSubShipQuantity().intValue();

                // 最终该单的已出库数量
                Integer outboundFinalNum = 0;
                if (x.getMainReturnOrder() != 1) {
                    outboundFinalNum = deliveryQuantity - shipQuantity;
                } else {
                    // 20220421按产品要求过滤退单数据
                    return;
                    //outboundFinalNum = (deliveryQuantity-shipQuantity)*-1;
                }
                String key = x.getMainShipAreaId() + "-" + x.getScItemOuterId();
                long outbound = resultMap.get(key) != null ? resultMap.get(key) : 0L;
                outbound = outbound + outboundFinalNum;
                resultMap.put(key, outbound);
            });

        } catch (Exception e) {
            log.error("getShipQuantity_error={}", e);
        }
        return resultMap;
    }

    @FacadeInvoker
    public Map<String, Long> getNotArriveQuantity(OrganizationSDO companyOrg, Set<String> filterWarehouseId,Set<String> inventoryWarehouseAreaId) {
        if (ObjectUtils.isEmpty(companyOrg)) {
            return new HashMap<>();
        }
        Map<String, Long> resultMap = new HashMap<>();
        int start = 0;
        int limit = 500;
        Date todayDate = DateUtils.getFirstTime(new Date());
        QueryAllocateOrderDetailReportFtof1Request request = QueryAllocateOrderDetailReportFtof1Request.builder()
            .platformNullId(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())
           .mainReceiveAreaId(Lists.newArrayList(inventoryWarehouseAreaId))
            //.platformIds(Lists.newArrayList(platformIds))
           .applyOrgIds(Arrays.asList(companyOrg.getId()))
            .type(AllocateOrderTypeEnum.PLAN.getType())
            .subStatuss(Lists.newArrayList(AllocateOrderStatus.DRAFT.getValue(),
                AllocateOrderStatus.Shipment_Processing.getValue(),
                AllocateOrderStatus.Part_Shipped.getValue(),
                AllocateOrderStatus.Received.getValue(),
                AllocateOrderStatus.Shipped.getValue(),
                AllocateOrderStatus.Receive_Processing.getValue(),
                AllocateOrderStatus.Part_Received.getValue(),
                AllocateOrderStatus.WAIT_PUSH.getValue(),
                AllocateOrderStatus.CLOSED_AND_PARTSHIPPED.getValue(),
                AllocateOrderStatus.CLOSED_AND_PARTRECEIVED.getValue()))
            .startTime(DateUtils.parse(DomUtil.getRollbackDate(todayDate, -90)))
            .endTime(DateUtils.getLatestTime(todayDate))
            .start(start)
            .limit(limit)
            .build();
        try {
            Result<List<OarsAllocateOrderDetailReportFtof1>> listResult = oarsAllocateOrderDetailReportFtof1Service.queryAllocateOrderDetailReportFtof1(request);
            log.info("ecShareInventoryImportImpl_getNotArriveQuantity_query_request={},size={}",JSONObject.toJSONString(request), listResult.getTotal());
            int allPage = listResult.getTotal() / limit;
            if (listResult.getTotal() % limit > 0) {
                allPage += 1;
            }
            if (ObjectUtils.isEmpty(listResult)) {
                return new HashMap<>();
            }
            List<OarsAllocateOrderDetailReportFtof1> orderDetailReportFtof1s = listResult.getResult();
            if (org.springframework.util.CollectionUtils.isEmpty(orderDetailReportFtof1s)) {
                return new HashMap<>();
            }
            for (int i = 1; i < allPage; i++) {
                start = limit * i;
                request.setStart(start);
                Result<List<OarsAllocateOrderDetailReportFtof1>> listResult1 = oarsAllocateOrderDetailReportFtof1Service.queryAllocateOrderDetailReportFtof1(request);
                if (!ObjectUtils.isEmpty(listResult1) && !org.springframework.util.CollectionUtils.isEmpty(listResult1.getResult())) {
                    orderDetailReportFtof1s.addAll(listResult1.getResult());
                }
            }

            orderDetailReportFtof1s.forEach(x -> {
                // 过滤含有"到场"字样的调拨单数据
                if (filterWarehouseId.contains(x.getMainReceiveAreaId())) {
                    return;
                }
                if(!inventoryWarehouseAreaId.contains(x.getMainReceiveAreaId())){
                    return;
                }
                // 订单数量
                Integer quantity = StringUtils.isEmpty(x.getSubQuantity()) ? 0 : new BigDecimal(x.getSubQuantity()).intValue();
                // 发货数量
                Integer shipQuantity = StringUtils.isEmpty(x.getSubShipQuantity()) ? 0: x.getSubShipQuantity().intValue();
                // 收货数量
                Integer receiveQuantity = StringUtils.isEmpty(x.getSubReceiveQuantity()) ? 0: x.getSubReceiveQuantity().intValue();
                // 最终该单的调拨未在途
                Integer notArriveFinalNum = 0;
                if (x.getMainReturnOrder() != 1) {
                    if (shipQuantity.compareTo(quantity) <= 0) {
                        notArriveFinalNum = quantity - receiveQuantity;
                    } else {
                        notArriveFinalNum = shipQuantity - receiveQuantity;
                    }
                } else {
                    /*if (shipQuantity.compareTo(quantity) <= 0) {
                        notArriveFinalNum = (quantity-receiveQuantity)*-1;
                    }else{
                        notArriveFinalNum = (shipQuantity-receiveQuantity)*-1;
                    }*/
                    // 20220419按产品要求计划调拨单跳过逆向单
                    return;
                }

                //String key = StringUtils.isEmpty(orderDetailReportFtof1.getExtEcPlatform()) ?
                // OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID() : orderDetailReportFtof1.getExtEcPlatform();
                String key = x.getMainReceiveAreaId() + "-" + x.getScItemOuterId();
                long notArrive = resultMap.get(key) != null ? resultMap.get(key) : 0L;
                notArrive = notArrive + notArriveFinalNum;
                resultMap.put(key, notArrive);
            });

        } catch (Exception e) {
            log.error("getNotArriveQuantity_error={}", e);
        }
        return resultMap;
    }

    private EcInventoryDetail collectInventoryDetail(Map.Entry<String, List<WarehouseInventory>> entryItem,
        Map<String, GoodsDO> goodsDOMap, Map<String, Long> shipQuantityMap, Map<String, Long> notArriveQuantityMap) {
        String goodsId = entryItem.getKey();
        GoodsDO goodsDO = goodsDOMap.get(goodsId);
        if (goodsDO == null) {
            log.info("ecShareInventoryImportImpl_goods_exist_ecWarehouseInventory_but_scItem_id_error={}", goodsId);
            return null;
        }
        Integer guaranteePeriod = goodsDO.getGuaranteePeriod();
        List<WarehouseInventory> inventoryList = entryItem.getValue();
        EcInventoryDetail detail = new EcInventoryDetail();
        detail.setWarehouseId(inventoryList.get(0).getWarehouseAreaId());
        detail.setGoodsId(goodsDO.getGoodsId());
        detail.setOuterItemId(goodsDO.getOuterItemId());
        detail.setGoodsName(goodsDO.getGoodsName());
        detail.setCategoryId(goodsDO.getCategoryId());
        detail.setCategoryName(goodsDO.getCategoryName());
        detail.setStatisticalDate(DomUtil.getToday());
        Long totalQuantity = inventoryList.stream().mapToLong(WarehouseInventory::getTotalQuantity).sum();
        detail.setTotalQuantity(totalQuantity);
        Long frozenQuantity = inventoryList.stream().mapToLong(WarehouseInventory::getFrozenQuantity).sum();
        Long inspectQuantity = inventoryList.stream().mapToLong(WarehouseInventory::getInspectQuantity).sum();
        Long availableQuantity = totalQuantity - frozenQuantity - inspectQuantity;//可用库存=总库存-冻结库存-质检库存
        detail.setAvailableQuantity(availableQuantity);
        detail.setWithholdingQuantity(
            inventoryList.stream().mapToLong(WarehouseInventory::getWithholdingQuantity).sum());
        detail.setOnwayQuantity(inventoryList.stream().mapToLong(WarehouseInventory::getOnwayQuantity).sum());
        detail.setFourthExpiredQuantity(inventoryList.stream().filter(
            x -> DomUtil.exceedFourthExpired(x.getDom(), guaranteePeriod))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setThirdExpiredQuantity(inventoryList.stream().filter(
            x -> DomUtil.exceedThirdExpired(x.getDom(), guaranteePeriod))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setApproachExpiredQuantity(inventoryList.stream().filter(
            x -> DomUtil.approachExpired4Ec(x.getDom(), guaranteePeriod))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setNormalQuantity(inventoryList.stream().filter(
            x -> DomUtil.lessFourthExpired(x.getDom(), guaranteePeriod))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setExceedThreeMonthsQuantity(inventoryList.stream().filter(x -> DomUtil.threeMonthsAgo(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setEarlyTwoMonthsQuantity(inventoryList.stream().filter(x -> DomUtil.twoMonthsAgoEarly(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setMidTwoMonthsQuantity(inventoryList.stream().filter(x -> DomUtil.twoMonthsAgoMid(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setLateTwoMonthsQuantity(inventoryList.stream().filter(x -> DomUtil.twoMonthsAgoLate(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setEarlyOneMonthQuantity(inventoryList.stream().filter(x -> DomUtil.oneMonthAgoEarly(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setMidOneMonthQuantity(inventoryList.stream().filter(x -> DomUtil.oneMonthAgoMid(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        detail.setLateOneMonthQuantity(inventoryList.stream().filter(x -> DomUtil.oneMonthAgoLate(x.getDom()))
            .mapToLong(WarehouseInventory::getAvailableQuantity).sum());
        String key = detail.getWarehouseId() + "-" + detail.getOuterItemId();
        Long shipQuantity = 0L;
        Long notArriveQuantity = 0L;
        if (shipQuantityMap.get(key) == null) {
            log.info("ecShareInventoryImportImpl_shipQuantityMap_get(key)_is_null,key={}", key);
        } else {
            shipQuantity = shipQuantityMap.get(key);
            shipQuantityMap.remove(key);
        }
        if (notArriveQuantityMap.get(key) == null) {
            log.info("ecShareInventoryImportImpl_notArriveQuantityMap_get(key)_is_null,key={}", key);
        } else {
            notArriveQuantity = notArriveQuantityMap.get(key);
            notArriveQuantityMap.remove(key);
        }
        detail.setShipQunatity(shipQuantity);
        detail.setNotArriveQuantity(notArriveQuantity);
        return detail;
    }

    /**
     * 获取 送达方id ： 仓库 id
     *
     * @param customerAddressIds
     * @return
     */
    private Map<String, String> getCustomerAddressWarehouse(List<String> customerAddressIds) {
        // 送达方id ：仓库 id
        Map<String, String> map = new HashMap<>();
        BatchQueryByIdsRequest request = BatchQueryByIdsRequest.builder()
            .idList(customerAddressIds)
            .build();
        Result<List<CustomerAddress>> listResult = customerAddressService.batchQueryByIds(request);
        if (ObjectUtils.isEmpty(listResult)) {
            return map;
        }
        List<CustomerAddress> result = listResult.getResult();
        if (CollectionUtils.isEmpty(result)) {
            return map;
        }

        // 送达code ： 送达方id
        Map<String, String> codeToCustomerAddressId = new HashMap<>();
        result.forEach(customerAddress -> {
            codeToCustomerAddressId.put(customerAddress.getAddressCode(), customerAddress.getId().toString());
        });

        Set<String> customerAddressCode = result.stream().map(CustomerAddress::getAddressCode).collect(
            Collectors.toSet());
        OuiWareshouseIndexRequest wareshouseIndexRequest = OuiWareshouseIndexRequest.builder()
            .sapDeliveryBPCodes(new ArrayList(customerAddressCode))
            .build();
        Result<List<OuiWarehouse>> ouiWarehouseListResult = otsUnifiedInventoryService.ouiWareshouseIndex(
            wareshouseIndexRequest);
        if (ObjectUtils.isEmpty(ouiWarehouseListResult)) {
            log.info("查询送达方对应的仓库为空，入参：{}", JSON.toJSONString(wareshouseIndexRequest));
            return map;
        }
        List<OuiWarehouse> warehouseList = ouiWarehouseListResult.getResult();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(warehouseList)) {
            log.info("查询送达方对应的仓库为空，入参：{}", JSON.toJSONString(wareshouseIndexRequest));
            return map;
        }

        warehouseList.forEach(ouiWarehouse -> {
            String s = codeToCustomerAddressId.get(ouiWarehouse.getSapDeliveryBPCode());
            if (!StringUtils.isEmpty(s)) {
                map.put(s, ouiWarehouse.getId().toString());
            }
        });
        return map;
    }

    /**
     * 根据 code 查询 组织
     *
     * @param code
     * @return
     */
    public OrganizationSDO allocateOrderByCode(String code) {
        BaselineGetOrganizationByOutCodes2Request request = BaselineGetOrganizationByOutCodes2Request.builder()
            .outCodes(Arrays.asList(code))
            .build();
        BaselineGetOrganizationByOutCodes2Response res = baseDataService.baselineGetOrganizationByOutCodes2(request);
        if (ObjectUtils.isEmpty(res)) {
            return null;
        }
        List<OrganizationSDO> result = res.getResult();
        if (org.springframework.util.CollectionUtils.isEmpty(result)) {
            return null;
        }
        return result.get(0);
    }

    private EcInventoryStats collectInventoryStats(List<EcInventoryDetail> detailList) {
        EcInventoryStats stats = new EcInventoryStats();
        stats.setDepartmentCode(detailList.get(0).getDepartmentCode());
        stats.setDepartmentName(detailList.get(0).getDepartmentName());
        stats.setPlatformCode(detailList.get(0).getPlatformCode());
        stats.setPlatformName(detailList.get(0).getPlatformName());
        stats.setWarehouseId(detailList.get(0).getWarehouseId());
        stats.setCode(detailList.get(0).getCode());
        stats.setWarehouseName(detailList.get(0).getWarehouseName());
        stats.setStatisticalDate(DomUtil.getToday());
        stats.setTotalQuantity(detailList.stream().mapToLong(EcInventoryDetail::getTotalQuantity).sum());
        stats.setAvailableQuantity(detailList.stream().mapToLong(EcInventoryDetail::getAvailableQuantity).sum());
        stats.setWithholdingQuantity(detailList.stream().mapToLong(EcInventoryDetail::getWithholdingQuantity).sum());
        stats.setOnwayQuantity(detailList.stream().mapToLong(EcInventoryDetail::getOnwayQuantity).sum());
        stats.setNotArriveQuantity(detailList.stream().mapToLong(EcInventoryDetail::getNotArriveQuantity).sum());
        stats.setFourthExpiredQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getFourthExpiredQuantity).sum());
        stats.setThirdExpiredQuantity(detailList.stream().mapToLong(EcInventoryDetail::getThirdExpiredQuantity).sum());
        stats.setApproachExpiredQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getApproachExpiredQuantity).sum());
        stats.setNormalQuantity(detailList.stream().mapToLong(EcInventoryDetail::getNormalQuantity).sum());
        stats.setExceedThreeMonthsQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getExceedThreeMonthsQuantity).sum());
        stats.setEarlyTwoMonthsQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getEarlyTwoMonthsQuantity).sum());
        stats.setMidTwoMonthsQuantity(detailList.stream().mapToLong(EcInventoryDetail::getMidTwoMonthsQuantity).sum());
        stats.setLateTwoMonthsQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getLateTwoMonthsQuantity).sum());
        stats.setEarlyOneMonthQuantity(
            detailList.stream().mapToLong(EcInventoryDetail::getEarlyOneMonthQuantity).sum());
        stats.setMidOneMonthQuantity(detailList.stream().mapToLong(EcInventoryDetail::getMidOneMonthQuantity).sum());
        stats.setLateOneMonthQuantity(detailList.stream().mapToLong(EcInventoryDetail::getLateOneMonthQuantity).sum());
        return stats;
    }

    private void initZeroInventoryQuantity(EcInventoryDetail detail, EcInventoryStats stats) {
        if(Objects.nonNull(detail)){
            detail.setTotalQuantity(0L);
            detail.setAvailableQuantity(0L);
            detail.setWithholdingQuantity(0L);
            detail.setOnwayQuantity(0L);
            //detail.setNotArriveQuantity(0L);
            detail.setFourthExpiredQuantity(0L);
            detail.setThirdExpiredQuantity(0L);
            detail.setApproachExpiredQuantity(0L);
            detail.setNormalQuantity(0L);
            detail.setExceedThreeMonthsQuantity(0L);
            detail.setEarlyTwoMonthsQuantity(0L);
            detail.setMidTwoMonthsQuantity(0L);
            detail.setLateTwoMonthsQuantity(0L);
            detail.setEarlyOneMonthQuantity(0L);
            detail.setMidOneMonthQuantity(0L);
            detail.setLateOneMonthQuantity(0L);
            detail.setGmt_modified(new Date());
        }
        if(Objects.nonNull(stats)){
            stats.setTotalQuantity(0L);
            stats.setAvailableQuantity(0L);
            stats.setWithholdingQuantity(0L);
            stats.setOnwayQuantity(0L);
            //stats.setNotArriveQuantity(0L);
            stats.setFourthExpiredQuantity(0L);
            stats.setThirdExpiredQuantity(0L);
            stats.setApproachExpiredQuantity(0L);
            stats.setNormalQuantity(0L);
            stats.setExceedThreeMonthsQuantity(0L);
            stats.setEarlyTwoMonthsQuantity(0L);
            stats.setMidTwoMonthsQuantity(0L);
            stats.setLateTwoMonthsQuantity(0L);
            stats.setEarlyOneMonthQuantity(0L);
            stats.setMidOneMonthQuantity(0L);
            stats.setLateOneMonthQuantity(0L);
            stats.setGmt_modified(new Date());
        }
    }

    private Boolean isZeroInventoryQuantity(EcInventoryDetail detail, EcInventoryStats stats) {
        if(Objects.nonNull(detail)){
            return detail.getTotalQuantity().equals(0L)
                    && detail.getAvailableQuantity().equals(0L)
                    && detail.getWithholdingQuantity().equals(0L)
                    && detail.getOnwayQuantity().equals(0L)
                    && detail.getFourthExpiredQuantity().equals(0L)
                    && detail.getThirdExpiredQuantity().equals(0L)
                    && detail.getApproachExpiredQuantity().equals(0L)
                    && detail.getNormalQuantity().equals(0L)
                    && detail.getExceedThreeMonthsQuantity().equals(0L)
                    && detail.getEarlyTwoMonthsQuantity().equals(0L)
                    && detail.getMidTwoMonthsQuantity().equals(0L)
                    && detail.getLateTwoMonthsQuantity().equals(0L)
                    && detail.getEarlyOneMonthQuantity().equals(0L)
                    && detail.getMidOneMonthQuantity().equals(0L)
                    && detail.getLateOneMonthQuantity().equals(0L);
        }
        if(Objects.nonNull(stats)){
            return stats.getTotalQuantity().equals(0L)
                    && stats.getAvailableQuantity().equals(0L)
                    && stats.getWithholdingQuantity().equals(0L)
                    && stats.getOnwayQuantity().equals(0L)
                    && stats.getFourthExpiredQuantity().equals(0L)
                    && stats.getThirdExpiredQuantity().equals(0L)
                    && stats.getApproachExpiredQuantity().equals(0L)
                    && stats.getNormalQuantity().equals(0L)
                    && stats.getExceedThreeMonthsQuantity().equals(0L)
                    && stats.getEarlyTwoMonthsQuantity().equals(0L)
                    && stats.getMidTwoMonthsQuantity().equals(0L)
                    && stats.getLateTwoMonthsQuantity().equals(0L)
                    && stats.getEarlyOneMonthQuantity().equals(0L)
                    && stats.getMidOneMonthQuantity().equals(0L)
                    && stats.getLateOneMonthQuantity().equals(0L);
        }
        return false;
    }

    private void enrichPlatInfo(String warehouseAreaId, List<EcInventoryDetail> todoList,
        List<EcWarehouse> warehouseList) {
        todoList.stream().forEach(x -> {
            x.setPlatformCode(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());
            x.setPlatformName(OtsApplicationReportSdkConstants.OTHER_PLATFORM_NAME());
        });
        List<EcWarehouse> subList = warehouseList.stream().filter(s -> s.getWarehouseId().equals(warehouseAreaId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(subList)) {
            return;
        }
        todoList.stream().forEach(x -> {
            x.setSapFactoryCode(subList.get(0).getSapFactoryCode());
            x.setWarehouseCode(subList.get(0).getWarehouseCode());
            x.setPlatformCode(subList.get(0).getPlatformCode());
            x.setDepartmentCode(subList.get(0).getDepartmentCode());
            x.setDepartmentName(subList.get(0).getDepartmentName());
            x.setPlatformName(subList.get(0).getPlatformName());
            x.setWarehouseName(subList.get(0).getWarehouseName());
            x.setCode(subList.get(0).getCode());
        });
    }

    @FacadeInvoker
    private List<EcWarehouse> getEcWarehouseInfo( Set<String> inventoryWarehouseAreaId ) {
        SearchWarehouseForPlatformNewRequest request = new SearchWarehouseForPlatformNewRequest();
        request.setStart(0);
        request.setLimit(PAGE_SIZE_500);
        //request.setOrgCode("1171");
        SearchWarehouseForPlatformNewResponse response = bcOtsService.searchWarehouseForPlatformNew(request);
        log.info("ecShareInventoryImportImpl_getEcWarehouse_request={},size={}", JSON.toJSONString(request),
            response.getTotal());
        if (response == null || CollectionUtils.isEmpty(response.getResult())) {
            return Lists.newArrayList();
        }
        List result = response.getResult();
        int totalCnt = response.getTotal();
        if (totalCnt > PAGE_SIZE_500) {
            int totalPage = totalCnt / PAGE_SIZE_500;
            if (totalCnt % PAGE_SIZE_500 > 0) {
                totalPage++;
            }
            for (int pageNo = 1; pageNo < totalPage; pageNo++) {
                request.setStart(pageNo * PAGE_SIZE_500);
                response = bcOtsService.searchWarehouseForPlatformNew(request);
                if (response != null && CollectionUtils.isNotEmpty(response.getResult())) {
                    result.addAll(response.getResult());
                }
            }
        }
        List<JSONObject> res = Lists.newArrayList();
        result.forEach(o -> {
            JSONObject json = (JSONObject)JSONObject.toJSON(o);
            // 返回电商下的共享仓、工厂仓
            if (2 == json.getInteger("type") && "297930260929790508".equals(json.getString("saleOrgId")) || 5 == json
                .getInteger("type")) {
                res.add(json);
            }
        });
        // 销售部门id
        List<String> sapSaleDepartments = new ArrayList<>();
        res.forEach(json -> {
            Map<String, String> map = JSONObject.parseObject(json.getString("feature"),
                new TypeReference<Map<String, String>>() {});
            String sapSaleDepartment = map.get("sapSaleDepartment");
            if (!StringUtils.isEmpty(sapSaleDepartment)) {
                sapSaleDepartments.add(sapSaleDepartment);
            }
        });
        // 销售部门id：销售部门名称
        Map<String, String> sapSaleDepartmentsMap = allocateOrderByCodes(
            sapSaleDepartments.stream().distinct().collect(Collectors.toList()));

        // 电商平台id
        List<String> platformIds = new ArrayList<>();
        res.forEach(json -> {
            Map<String, String> map = JSONObject.parseObject(json.getString("feature"),
                new TypeReference<Map<String, String>>() {});
            String sapSaleDepartment = map.get("ecPlatform");
            if (!StringUtils.isEmpty(sapSaleDepartment)) {
                platformIds.add(sapSaleDepartment);
            }
        });
        // 电商平台id：电商平台名称
        Map<String, String> platformMap = this.getPlatFormOfEC(platformIds);
        //填充数据
        List<EcWarehouse> warehouseList = new ArrayList<>();
        for (JSONObject json : res) {
            String warehouseId=json.getString("id");
            if(!inventoryWarehouseAreaId.contains(warehouseId)) {
                continue;
            }
            EcWarehouse warehouse = new EcWarehouse();
            warehouse.setCode(json.getString("code"));
            warehouse.setWarehouseId(warehouseId);
            warehouse.setWarehouseName(json.getString("name"));
            warehouse.setSapFactoryCode(json.getString("sapFactoryCode"));
            warehouse.setWarehouseCode(json.getString("warehouseCode"));
            Map<String, String> map = JSONObject.parseObject(json.getString("feature"),
                new TypeReference<Map<String, String>>() {
                });
            if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("ecPlatform"))) {
                String platformCode = map.get("ecPlatform");
                warehouse.setPlatformCode(platformCode);
                warehouse.setPlatformName(platformMap.get(platformCode));
            } else {
                warehouse.setPlatformCode(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());
                warehouse.setPlatformName(OtsApplicationReportSdkConstants.OTHER_PLATFORM_NAME());
            }
            String sapSaleDepartment = map.get("sapSaleDepartment");
            warehouse.setDepartmentCode(sapSaleDepartment);
            String sapSaleDepartmentName = sapSaleDepartmentsMap.get(sapSaleDepartment);
            warehouse.setDepartmentName(sapSaleDepartmentName);
            warehouseList.add(warehouse);
        }
        return warehouseList;
    }

    //取电商平台
    private Map<String, String> getPlatFormOfEC(List ids) {
        Map<String, String> map = new HashMap<>();
        BaselineBatchQueryPlatformsRequest request = new BaselineBatchQueryPlatformsRequest();
        request.setPlatformIds(ids);
        try {
            Object result = baseDataService.baselineBatchQueryPlatforms(request);
            if (result == null) {
                return map;
            }
            log.info("ecShareInventoryImportImpl_baselineBatchQueryPlatforms_result={}", JSON.toJSONString(result));
            JSONObject json = (JSONObject)JSONObject.toJSON(result);
            JSONArray array = json.getJSONArray("result");
            for (Object o : array) {
                JSONObject temp = (JSONObject)JSONObject.toJSON(o);
                map.put(temp.getString("platformId"), temp.getString("platformName"));
            }
            return map;
        } catch (Exception e) {
            log.error("ecShareInventoryImportImpl_baselineBatchQueryPlatforms_error,cause={}", e);
        }
        return map;
    }

    //判断是否当前待处理记录是否已存在
    private EcInventoryDetail existedOfList(EcInventoryDetail todo, List<EcInventoryDetail> existedList) {
        if (CollectionUtils.isEmpty(existedList)) {
            return null;
        }
        for (EcInventoryDetail existed : existedList) {
            if (existed.getGoodsId().equals(todo.getGoodsId())) {
                return existed;
            }
        }
        return null;
    }

    //判断是否当前待处理记录是否已存在
    private EcInventoryStats existedOfList(EcInventoryStats todo, List<EcInventoryStats> existedList) {
        if (CollectionUtils.isEmpty(existedList)) {
            return null;
        }
        for (EcInventoryStats existed : existedList) {
            if (existed.getWarehouseId().equals(todo.getWarehouseId())) {
                return existed;
            }
        }
        return null;
    }

    /**
     * 根据 ids：组织名称
     *
     * @param ids
     * @return
     */
    private Map<String, String> allocateOrderByCodes(List<String> ids) {
        BaselineGetOrganizationByIds2Request request = BaselineGetOrganizationByIds2Request.builder()
            .ids(ids)
            .build();
        BaselineGetOrganizationByIds2Response res = baseDataService.baselineGetOrganizationByIds2(request);
        if (ObjectUtils.isEmpty(res)) {
            return new HashMap<>();
        }
        List<OrganizationSDO> result = res.getResult();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return new HashMap<>();
        }
        Map<String, String> map = new HashMap<>();
        result.forEach(sdo -> {
            map.put(sdo.getId(), sdo.getName());
        });
        return map;
    }

    //取库存记录总数
    private int getInventoryTotal(InventoryTypeEnum typeEnum) {
        GetListWarehouseStockRequest request = new GetListWarehouseStockRequest();
        request.setPage(PAGE_NO_1);
        request.setSize(PAGE_SIZE_500);
        // 当前类型与库存侧列表页查询保持一致
        request.setType(String.valueOf(typeEnum.getType()));
        /**
         * 库存列表中的库存查询为汇总库存，类型为1
         */
        //request.setType(SUMMARY_INVENTORY_TYPE);
        /**
         * 20220411
         * 按产品要求，目前写死内蒙古数科数字营销有限公司组织id，只查询电商数科数据
         */
        request.setBizUnitIdList(Lists.newArrayList(NM_MARKETING_LTD));
        // 与库存侧列表页查询保持一致
        //request.setSearchForPage(Boolean.TRUE);
        return otsUnifiedInventoryService.getListWarehouseStock(request).getTotal();
    }

    @Data
    private class EcWarehouse {
        private String code;
        private String warehouseId;
        private String warehouseName;
        private String sapFactoryCode;
        private String warehouseCode;
        private String departmentCode;
        private String departmentName;
        private String platformCode;
        private String platformName;
    }

    /**
     * 当月第一天
     *
     * @param timeFlag 是否带时分秒， true是
     * @return
     */
    public static String getFirstDay(boolean timeFlag) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        Date theDate = calendar.getTime();

        GregorianCalendar gcLast = (GregorianCalendar)Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, 1);
        String day_first = df.format(gcLast.getTime());
        StringBuffer str = new StringBuffer().append(day_first);
        if (timeFlag) {
            str.append(" 00:00:00");
        }
        return str.toString();
    }

    /**
     * 获取逻辑仓编码
     *
     * @return 编码
     */
    private Set<String> getInventoryWarehouseAreaId(List<WarehouseInventory> inventoryList) {
        return inventoryList.stream()
            .filter(x -> org.apache.commons.lang3.StringUtils.isNotBlank(x.getWarehouseAreaId()))
            .map(WarehouseInventory::getWarehouseAreaId)
            .collect(Collectors.toSet());
    }

    /**
     * 获取逻辑仓中含有"到场"字样的仓库id
     *
     * @param warehouseList 电商下的逻辑仓
     * @return 含有"到场"字样的仓库id
     */
    private Set<String> filterWarehouseAreaId(List<EcWarehouse> warehouseList) {
        return warehouseList.stream().filter(warehouse -> {
            if (StringUtils.isEmpty(warehouse.getWarehouseName())) {
                return Boolean.FALSE;
            }
            return warehouse.getWarehouseName().contains(FILTER_STR);
        }).map(EcWarehouse::getWarehouseId).collect(Collectors.toSet());
    }

    /**
     * 重写库存明细数据
     *
     * @param entryItem            总部销售、计划调拨
     * @param goodsDOMap           货品信息
     * @param notArriveQuantityMap 调拨未到货数量
     * @return 库存明细
     */
    private EcInventoryDetail collectInventoryDetail(Map.Entry<String, Long> entryItem, Map<String, GoodsDO> goodsDOMap,
        Map<String, Long> notArriveQuantityMap) {
        String[] split = entryItem.getKey().split("-");
        String warehouseAreaId = split[0];
        String outerItem = split[1];
        GoodsDO goodsDO = goodsDOMap.get(outerItem);
        if (goodsDO == null) {
            log.info("ecShareInventoryImportImpl_goods_exist_collectInventoryDetail_error={},{}", outerItem,
                notArriveQuantityMap);
            return null;
        }
        EcInventoryDetail detail = new EcInventoryDetail();
        detail.setWarehouseId(warehouseAreaId);
        detail.setGoodsId(goodsDO.getGoodsId());
        detail.setOuterItemId(goodsDO.getOuterItemId());
        detail.setGoodsName(goodsDO.getGoodsName());
        detail.setCategoryId(goodsDO.getCategoryId());
        detail.setCategoryName(goodsDO.getCategoryName());
        detail.setStatisticalDate(DomUtil.getToday());
        detail.setTotalQuantity(0L);
        //可用库存=总库存-冻结库存-质检库存
        detail.setAvailableQuantity(0L);
        detail.setWithholdingQuantity(0L);
        detail.setOnwayQuantity(0L);
        detail.setFourthExpiredQuantity(0L);
        detail.setThirdExpiredQuantity(0L);
        detail.setApproachExpiredQuantity(0L);
        detail.setNormalQuantity(0L);
        detail.setExceedThreeMonthsQuantity(0L);
        detail.setEarlyTwoMonthsQuantity(0L);
        detail.setMidTwoMonthsQuantity(0L);
        detail.setLateTwoMonthsQuantity(0L);
        detail.setEarlyOneMonthQuantity(0L);
        detail.setMidOneMonthQuantity(0L);
        detail.setLateOneMonthQuantity(0L);
        String key = detail.getWarehouseId() + "-" + detail.getOuterItemId();
        Long shipQuantity = 0L;
        Long notArriveQuantity = 0L;
        if (MapUtils.isNotEmpty(notArriveQuantityMap)) {
            if (entryItem.getValue() == null) {
                log.info("ecShareInventoryImportImpl_collectInventoryDetail_shipQuantityMap_get(key)_is_null,key={}",
                    key);
            } else {
                shipQuantity = entryItem.getValue();
            }
            if (notArriveQuantityMap.get(key) != null) {
                notArriveQuantity = notArriveQuantityMap.get(key);
                notArriveQuantityMap.remove(key);
            }
        } else {
            if (entryItem.getValue() == null) {
                log.info(
                    "ecShareInventoryImportImpl_collectInventoryDetail_notArriveQuantityMap_get(key)_is_null,key={}",
                    key);
            } else {
                notArriveQuantity = entryItem.getValue();
            }
        }
        detail.setShipQunatity(shipQuantity);
        detail.setNotArriveQuantity(notArriveQuantity);
        return detail;
    }

    private Map<String, GoodsDO> parseOuterItemIdMap(Map<String, GoodsDO> goodsDOMap) {
        return goodsDOMap.values().stream()
            .collect(Collectors.toMap(GoodsDO::getOuterItemId, o -> o, (a, b) -> a));
    }
    private List<WarehouseInventory> formatQuantity(List<InventoryForAnalysisResp> beforFormatList) {
        List<WarehouseInventory> result = new ArrayList<>();
        for (InventoryForAnalysisResp x : beforFormatList) {
            WarehouseInventory y = new WarehouseInventory();
            y.setWarehouseAreaId(x.getWarehouseAreaId());
            y.setDom(x.getDom());
            y.setTotalQuantity(x.getTotalQuantity());
            y.setInspectQuantity(x.getInspectQuantity());
            y.setWithholdingQuantity(x.getWithholdingQuantity());
            y.setOnwayQuantity(x.getOnwayQuantity());
            y.setFrozenQuantity(x.getFrozenQuantity());
            y.setAvailableQuantity(x.getAvailableQuantity());
            y.setGoodsId(x.getGoodsId());
            result.add(y);
        }
        return result;
    }
    @Override
    public void reAnalysisReport(String statisDate) {

    }
}
